package dstree

import (
	"fmt"
)

type Dstree_Index_Settings struct {
	// Root_directory string
	// InitSegments   int16
	TimeseriesSize int16
	MaxLeafSize    int32
}

// type Series struct {
// 	ts        []Ts_type
// 	object_id string
// }

type Timeseries [][]Ts_type

type TS_data []*Timeseries

type Dstree_Index struct {
	Settings     *Dstree_Index_Settings
	TotalRecords uint64 //记录数量
	node_num     int64  //节点数量
	height       int64  //树高
	firstNode    *Dstree_Node
	// mtreeroot    *MTree_Node
	data        TS_data //存放数据
	objectIDmap map[string]string
	obCondition map[string]bool //map[objectID]是否存在
	deletednum  int
}

type Dstree_Proof struct {
	ObjectID []string
	Data     [][]float32
	VO       []string
}

func (index *Dstree_Index) Get_RootHash() []byte {
	return index.firstNode.Digest
}
func (index *Dstree_Index) Get_NodeNum() int64 {
	return index.node_num
}
func (index *Dstree_Index) Get_height() int64 {
	return index.height
}

// 初始化index
func DstreeIndexInit(settings *Dstree_Index_Settings) *Dstree_Index {
	index := Dstree_Index{
		Settings:     settings,
		node_num:     0,
		TotalRecords: 0,
		firstNode:    nil,
		objectIDmap:  make(map[string]string),
		obCondition:  make(map[string]bool),
		deletednum:   0,
	}
	index.data = make(TS_data, 0)
	index.firstNode = index.dstree_root_node_init(settings)
	index.firstNode.Digest = index.ads_construction(index.firstNode)
	return &index
}

func (index *Dstree_Index) dstree_root_node_init(setting *Dstree_Index_Settings) *Dstree_Node {
	//根节点被初始化时是一个叶节点
	node := index.dstree_leaf_node_init(1)
	ts_length := setting.TimeseriesSize
	segment_size := 1
	points := Calc_split_points(int(ts_length), int(segment_size))
	node.Node_init_segments(points, int(segment_size))
	node.Is_leaf = true
	node.Is_left = false
	return node
}

func (index *Dstree_Index) dstree_leaf_node_init(level int64) *Dstree_Node {
	//新节点计数++
	index.node_num++
	newdatablock := new(Timeseries)
	index.data = append(index.data, newdatablock)
	if level > index.height {
		index.height = level
	}
	newnode := Dstree_Node{
		Name:         fmt.Sprintf("N%d", index.node_num),
		Level:        level,
		Left_child:   nil,
		Right_child:  nil,
		Parent:       nil,
		data:         newdatablock,
		Is_leaf:      true,
		Split_Policy: Node_Split_Policy{0, 0, 0, 0},
	}
	return &newnode

}

func (index *Dstree_Index) InsertData(object_id string, timeseries []Ts_type) error {
	index.insert(timeseries)
	//index.PrintDSTree()
	hash := tsdataToHash(timeseries)
	index.objectIDmap[hash] = object_id
	index.obCondition[object_id] = true
	return nil
}

func (index *Dstree_Index) insert(timeseries []Ts_type) error {
	index.TotalRecords++
	node := index.firstNode
	for !node.Is_leaf {
		//更新内部节点统计数据
		node.update_node_statistics(timeseries)
		//导航到叶节点
		if node.Node_split_policy_route_to_left(timeseries) {
			node = node.Left_child
		} else {
			node = node.Right_child
		}

	}
	if node.Is_leaf {
		node.update_node_statistics(timeseries)
		index.append_ts_to_node(node, timeseries)
		//判断是否需要分裂
		//if split needed, split the node and refresh curr_node
		if node.Node_Size >= index.Settings.MaxLeafSize {
			var hs_split_point int16
			node.Split_Policy, hs_split_point = node.best_Split_Policy()
			var child_node_points []int16
			//小于0说明为h-split，即孩子节点point不变
			num_points := len(node.Node_Points)
			if hs_split_point < 0 {
				child_node_points = make([]int16, num_points)
				for i := 0; i < num_points; i++ {
					child_node_points[i] = node.Node_Points[i]
				}
			} else { //大于0 孩子节点node_point+1
				child_node_points = make([]int16, num_points+1)
				i := 0
				for i < num_points && node.Node_Points[i] < hs_split_point {
					child_node_points[i] = node.Node_Points[i]
					i++
				}
				child_node_points[i] = hs_split_point
				i++
				for i < (num_points + 1) {
					child_node_points[i] = node.Node_Points[i-1]
					i++
				}
			}
			// fmt.Printf("      child_node_points:%+v\n", child_node_points)
			//将原来节点中的序列分到孩子节点中
			index.split_Node(node, child_node_points)
			// fmt.Printf("      Get all time series in node")
			ts_list := index.get_all_time_series_in_node(node)
			// fmt.Printf("      routing ts to childNode\n")
			var idx int32
			for idx = 0; idx < index.Settings.MaxLeafSize; idx++ {
				if node.Node_split_policy_route_to_left(ts_list[idx]) {
					node.Left_child.update_node_statistics(ts_list[idx])
					index.append_ts_to_node(node.Left_child, ts_list[idx])
					//fmt.Printf("      Leftchild ts++\n")
				} else {
					node.Right_child.update_node_statistics(ts_list[idx])
					index.append_ts_to_node(node.Right_child, ts_list[idx])
					//fmt.Printf("      Rightchild ts++\n")
				}
			}
			//从timeserises中删除此节点对应数据
			// fmt.Printf("      Clear data in original node……\n")
			index.data = index.delete_data(node.data)
			node.data = nil
			node.Hs_split_points_num = int16(len(node.Hs_split_points))
			node.Node_Points_num = int16(len(node.Node_Points))
		}
		//更新ads
		index.update_insert_ads(node)
	}
	return nil
}

func (index *Dstree_Index) DeleteData(objectid string) error {
	fmt.Println("Dstree index delete object:", objectid)
	_, exists := index.obCondition[objectid]
	if !exists {
		return fmt.Errorf("object dosen't exist")
	} else {
		index.obCondition[objectid] = false
	}
	index.deletednum++
	return nil
}
func (index *Dstree_Index) isdeleted(object_id string) bool {

	if index.obCondition[object_id] {
		return false
	} else {
		return true
	}
}
func (index *Dstree_Index) update_insert_ads(node *Dstree_Node) {

	if !node.Is_leaf {
		//若为内部节点，插入过程中经过了分裂
		node.Left_child.Digest = Get_leafNode_hash(node.Left_child, *node.Left_child.data)
		node.Right_child.Digest = Get_leafNode_hash(node.Right_child, *node.Right_child.data)
		node.Digest = Get_internalNode_hash(node.Left_child.Digest, node.Right_child.Digest, node)
	} else {
		//没有经过分裂
		node.Digest = Get_leafNode_hash(node, *node.data)
	}

	parentnode := node.Parent
	//至下而上更新
	for parentnode != nil {
		parentnode.Digest = Get_internalNode_hash(parentnode.Left_child.Digest, parentnode.Right_child.Digest, parentnode)
		parentnode = parentnode.Parent
	}
}

func (index *Dstree_Index) delete_data(ts *Timeseries) TS_data {
	j := 0
	for _, v := range index.data {
		if v != ts {
			index.data[j] = v
			j++
		}
	}
	return index.data[:j]
}
func (index *Dstree_Index) split_Node(node *Dstree_Node, child_node_points []int16) {
	if !node.Is_leaf {
		return
	}
	//init children nodes
	node.Left_child = index.create_child_node(node)
	node.Left_child.Node_init_segments(child_node_points, len(child_node_points))
	node.Left_child.Is_left = true

	node.Right_child = index.create_child_node(node)
	node.Right_child.Node_init_segments(child_node_points, len(child_node_points))
	node.Right_child.Is_left = false
	//此节点成为内部节点
	node.Is_leaf = false
}

func (index *Dstree_Index) get_all_time_series_in_node(node *Dstree_Node) [][]Ts_type {
	temp_data := make([][]Ts_type, node.Node_Size)
	var i int32
	for i = 0; i < node.Node_Size; i++ {
		temp_data[i] = make([]Ts_type, index.Settings.TimeseriesSize)
		var j int16
		for j = 0; j < index.Settings.TimeseriesSize; j++ {
			temp_data[i][j] = (*node.data)[i][j]
		}
	}
	return temp_data
}

func (index *Dstree_Index) append_ts_to_node(node *Dstree_Node, timeseries []Ts_type) {
	//fmt.Printf("Appending ts to node\n")
	if node.data == nil {
		fmt.Printf("error : nodedata = nil")
		return
	}
	*node.data = append(*node.data, timeseries)
}

func (index *Dstree_Index) PrintDSTree() {
	fmt.Printf("              DsTree status:           \n")
	fmt.Printf("%-20s %d\n", "Node Number", index.node_num)
	fmt.Printf("%-20s %d\n", "Tree height", index.height)
	fmt.Printf("%-20s %d\n", "Leaf node Number", len(index.data))
	fmt.Printf("%-20s %d\n", "TotalRecords", index.TotalRecords)

	// fmt.Printf("              Print DsTree:           \n")
	// level := 0
	// LevelTraverse(index.firstNode, &level)
	// fmt.Printf("%-20s %v\n", "avglevel", float32(level)/float32(len(index.data)))
	// PrintMTtree(index.firstNode, index.mtreeroot)

}

func LevelTraverse(root *Dstree_Node, level *int) {
	queue := make([]*Dstree_Node, 0)
	queue = append(queue, root)
	for len(queue) != 0 {
		len := len(queue)
		for i := 0; i < len; i++ {
			node := queue[0]
			queue = queue[1:]
			node.PrintNode()
			if !node.Is_leaf {
				queue = append(queue, node.Left_child)
				queue = append(queue, node.Right_child)
			} else {
				*level += int(node.Level)
				*level -= 1
			}
		}
	}
}

func (node *Dstree_Node) PrintNode() {

	fmt.Printf("%-5s infomation:\n", node.Name)
	fmt.Printf("%-5s %-15s: %x\n", " ", "Digest", node.Digest)
	if node.Parent != nil {
		fmt.Printf("%-5s %-15s: %+v\n", " ", "Parents", node.Parent.Name)
	}

	// fmt.Printf("%-5s %-15s: %+v\n", " ", "sketch_len", len(node.Segment_Sketches[0].Indicators))
	// fmt.Printf("%-5s %-15s: %+v\n", " ", "node point", node.Node_Points_num)
	// fmt.Printf("%-5s %-15s: %+v\n", " ", "hs_node_point", node.Hs_split_points_num)

	// if node.Is_leaf {
	// 	fmt.Printf("%-5s %-15s: %d\n", " ", "leaf node size", node.Node_Size)
	// 	fmt.Printf("%-5s %-15s: %d\n", " ", "data start", node.DataStart)
	// 	for _, v := range *node.data {
	// 		fmt.Printf("%-5s %-15s: %v\n", " ", " ", v)
	// 	}
	// }
}
